Various hypercall fixes for x86_64.
Main todos: 1. mmu_updates/update_va_mapping hypercalls.
2. map perdomain_pt into Xen address space.
3. exception/interrupt callbacks to guest OS.
4. user-space ring 3 vs. guest-OS ring 3.
Signed-off-by: keir.fraser@cl.cam.ac.uk
static int alloc_segdesc_page(struct pfn_info *page)
{
- unsigned long *descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
+ struct desc_struct *descs;
int i;
+ descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
+
for ( i = 0; i < 512; i++ )
- if ( unlikely(!check_descriptor(&descs[i*2])) )
+ if ( unlikely(!check_descriptor(&descs[i])) )
goto fail;
unmap_domain_mem(descs);
+/*************************
+ * Descriptor Tables
+ */
+
+void destroy_gdt(struct exec_domain *ed)
+{
+ int i;
+ unsigned long pfn;
+
+ for ( i = 0; i < 16; i++ )
+ {
+ if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
+ put_page_and_type(&frame_table[pfn]);
+ ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
+ }
+}
+
+
+long set_gdt(struct exec_domain *ed,
+ unsigned long *frames,
+ unsigned int entries)
+{
+ struct domain *d = ed->domain;
+ /* NB. There are 512 8-byte entries per GDT page. */
+ int i = 0, nr_pages = (entries + 511) / 512;
+ struct desc_struct *vgdt;
+ unsigned long pfn;
+
+ /* Check the first page in the new GDT. */
+ if ( (pfn = frames[0]) >= max_page )
+ goto fail;
+
+ /* The first page is special because Xen owns a range of entries in it. */
+ if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+ {
+ /* GDT checks failed: try zapping the Xen reserved entries. */
+ if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
+ goto fail;
+ vgdt = map_domain_mem(pfn << PAGE_SHIFT);
+ memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
+ NR_RESERVED_GDT_ENTRIES*8);
+ unmap_domain_mem(vgdt);
+ put_page_and_type(&frame_table[pfn]);
+
+ /* Okay, we zapped the entries. Now try the GDT checks again. */
+ if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+ goto fail;
+ }
+
+ /* Check the remaining pages in the new GDT. */
+ for ( i = 1; i < nr_pages; i++ )
+ if ( ((pfn = frames[i]) >= max_page) ||
+ !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+ goto fail;
+
+ /* Copy reserved GDT entries to the new GDT. */
+ vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
+ memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
+ gdt_table + FIRST_RESERVED_GDT_ENTRY,
+ NR_RESERVED_GDT_ENTRIES*8);
+ unmap_domain_mem(vgdt);
+
+ /* Tear down the old GDT. */
+ destroy_gdt(ed);
+
+ /* Install the new GDT. */
+ for ( i = 0; i < nr_pages; i++ )
+ ed->arch.perdomain_ptes[i] =
+ mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+
+ SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
+ SET_GDT_ENTRIES(ed, entries);
+
+ return 0;
+
+ fail:
+ while ( i-- > 0 )
+ put_page_and_type(&frame_table[frames[i]]);
+ return -EINVAL;
+}
+
+
+long do_set_gdt(unsigned long *frame_list, unsigned int entries)
+{
+ int nr_pages = (entries + 511) / 512;
+ unsigned long frames[16];
+ long ret;
+
+ if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
+ return -EINVAL;
+
+ if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
+ return -EFAULT;
+
+ LOCK_BIGLOCK(current->domain);
+
+ if ( (ret = set_gdt(current, frames, entries)) == 0 )
+ {
+ local_flush_tlb();
+ __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
+ }
+
+ UNLOCK_BIGLOCK(current->domain);
+
+ return ret;
+}
+
+
+long do_update_descriptor(
+ unsigned long pa, unsigned long word1, unsigned long word2)
+{
+ unsigned long pfn = pa >> PAGE_SHIFT;
+ struct desc_struct *gdt_pent, d;
+ struct pfn_info *page;
+ struct exec_domain *ed;
+ long ret = -EINVAL;
+
+ d.a = (u32)word1;
+ d.b = (u32)word2;
+
+ LOCK_BIGLOCK(current->domain);
+
+ if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(&d) ) {
+ UNLOCK_BIGLOCK(current->domain);
+ return -EINVAL;
+ }
+
+ page = &frame_table[pfn];
+ if ( unlikely(!get_page(page, current->domain)) ) {
+ UNLOCK_BIGLOCK(current->domain);
+ return -EINVAL;
+ }
+
+ /* Check if the given frame is in use in an unsafe context. */
+ switch ( page->u.inuse.type_info & PGT_type_mask )
+ {
+ case PGT_gdt_page:
+ /* Disallow updates of Xen-reserved descriptors in the current GDT. */
+ for_each_exec_domain(current->domain, ed) {
+ if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
+ (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
+ (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
+ goto out;
+ }
+ if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
+ goto out;
+ break;
+ case PGT_ldt_page:
+ if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
+ goto out;
+ break;
+ default:
+ if ( unlikely(!get_page_type(page, PGT_writable_page)) )
+ goto out;
+ break;
+ }
+
+ /* All is good so make the update. */
+ gdt_pent = map_domain_mem(pa);
+ memcpy(gdt_pent, &d, 8);
+ unmap_domain_mem(gdt_pent);
+
+ put_page_type(page);
+
+ ret = 0; /* success */
+
+ out:
+ put_page(page);
+
+ UNLOCK_BIGLOCK(current->domain);
+
+ return ret;
+}
+
+
+
/*************************
* Writable Pagetables
*/
if ( !GUEST_FAULT(regs) )
goto xen_fault;
+#ifndef NDEBUG
+ if ( (ed->arch.traps[trapnr].address == 0) && (ed->domain->id == 0) )
+ goto xen_fault;
+#endif
+
ti = current->arch.traps + trapnr;
tb->flags = TBF_EXCEPTION;
tb->cs = ti->cs;
if ( !GUEST_FAULT(regs) )
goto xen_fault;
+#ifndef NDEBUG
+ if ( (ed->arch.traps[TRAP_page_fault].address == 0) && (d->id == 0) )
+ goto xen_fault;
+#endif
+
propagate_page_fault(addr, regs->error_code);
return 0;
return 0;
#endif
+#ifndef NDEBUG
+ if ( (ed->arch.traps[TRAP_gp_fault].address == 0) &&
+ (ed->domain->id == 0) )
+ goto gp_in_kernel;
+#endif
+
/* Pass on GPF as is. */
ti = current->arch.traps + 13;
tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
}
+#if defined(__i386__)
+#define DB_VALID_ADDR(_a) \
+ ((_a) <= (PAGE_OFFSET - 4))
+#elif defined(__x86_64__)
+#define DB_VALID_ADDR(_a) \
+ ((_a) >= HYPERVISOR_VIRT_END) || ((_a) <= (HYPERVISOR_VIRT_START-8))
+#endif
long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
{
int i;
switch ( reg )
{
case 0:
- if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ if ( !DB_VALID_ADDR(value) ) return -EPERM;
if ( p == current )
__asm__ ( "mov %0, %%db0" : : "r" (value) );
break;
case 1:
- if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ if ( !DB_VALID_ADDR(value) ) return -EPERM;
if ( p == current )
__asm__ ( "mov %0, %%db1" : : "r" (value) );
break;
case 2:
- if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ if ( !DB_VALID_ADDR(value) ) return -EPERM;
if ( p == current )
__asm__ ( "mov %0, %%db2" : : "r" (value) );
break;
case 3:
- if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+ if ( !DB_VALID_ADDR(value) ) return -EPERM;
if ( p == current )
__asm__ ( "mov %0, %%db3" : : "r" (value) );
break;
/* Returns TRUE if given descriptor is valid for GDT or LDT. */
-int check_descriptor(unsigned long *d)
+int check_descriptor(struct desc_struct *d)
{
- unsigned long base, limit, a = d[0], b = d[1];
+ unsigned long base, limit;
+ u32 a = d->a, b = d->b;
/* A not-present descriptor will always fault, so is safe. */
if ( !(b & _SEGMENT_P) )
if ( !(b & _SEGMENT_G) )
goto bad; /* too dangerous; too hard to work out... */
limit = (limit >> 12) - 1;
- d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
- d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
+ d->a &= ~0x0ffff; d->a |= limit & 0x0ffff;
+ d->b &= ~0xf0000; d->b |= limit & 0xf0000;
}
}
}
-void destroy_gdt(struct exec_domain *ed)
-{
- int i;
- unsigned long pfn;
-
- for ( i = 0; i < 16; i++ )
- {
- if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
- put_page_and_type(&frame_table[pfn]);
- ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
- }
-}
-
-
-long set_gdt(struct exec_domain *ed,
- unsigned long *frames,
- unsigned int entries)
-{
- struct domain *d = ed->domain;
- /* NB. There are 512 8-byte entries per GDT page. */
- int i = 0, nr_pages = (entries + 511) / 512;
- struct desc_struct *vgdt;
- unsigned long pfn;
-
- /* Check the first page in the new GDT. */
- if ( (pfn = frames[0]) >= max_page )
- goto fail;
-
- /* The first page is special because Xen owns a range of entries in it. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- {
- /* GDT checks failed: try zapping the Xen reserved entries. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
- goto fail;
- vgdt = map_domain_mem(pfn << PAGE_SHIFT);
- memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
- NR_RESERVED_GDT_ENTRIES*8);
- unmap_domain_mem(vgdt);
- put_page_and_type(&frame_table[pfn]);
-
- /* Okay, we zapped the entries. Now try the GDT checks again. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- goto fail;
- }
-
- /* Check the remaining pages in the new GDT. */
- for ( i = 1; i < nr_pages; i++ )
- if ( ((pfn = frames[i]) >= max_page) ||
- !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- goto fail;
-
- /* Copy reserved GDT entries to the new GDT. */
- vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
- memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
- gdt_table + FIRST_RESERVED_GDT_ENTRY,
- NR_RESERVED_GDT_ENTRIES*8);
- unmap_domain_mem(vgdt);
-
- /* Tear down the old GDT. */
- destroy_gdt(ed);
-
- /* Install the new GDT. */
- for ( i = 0; i < nr_pages; i++ )
- ed->arch.perdomain_ptes[i] =
- mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
-
- SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
- SET_GDT_ENTRIES(ed, entries);
-
- return 0;
-
- fail:
- while ( i-- > 0 )
- put_page_and_type(&frame_table[frames[i]]);
- return -EINVAL;
-}
-
-
-long do_set_gdt(unsigned long *frame_list, unsigned int entries)
-{
- int nr_pages = (entries + 511) / 512;
- unsigned long frames[16];
- long ret;
-
- if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
- return -EINVAL;
-
- if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
- return -EFAULT;
-
- LOCK_BIGLOCK(current->domain);
-
- if ( (ret = set_gdt(current, frames, entries)) == 0 )
- {
- local_flush_tlb();
- __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
- }
-
- UNLOCK_BIGLOCK(current->domain);
-
- return ret;
-}
-
-
-long do_update_descriptor(
- unsigned long pa, unsigned long word1, unsigned long word2)
-{
- unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
- struct pfn_info *page;
- struct exec_domain *ed;
- long ret = -EINVAL;
-
- d[0] = word1;
- d[1] = word2;
-
- LOCK_BIGLOCK(current->domain);
-
- if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) ) {
- UNLOCK_BIGLOCK(current->domain);
- return -EINVAL;
- }
-
- page = &frame_table[pfn];
- if ( unlikely(!get_page(page, current->domain)) ) {
- UNLOCK_BIGLOCK(current->domain);
- return -EINVAL;
- }
-
- /* Check if the given frame is in use in an unsafe context. */
- switch ( page->u.inuse.type_info & PGT_type_mask )
- {
- case PGT_gdt_page:
- /* Disallow updates of Xen-reserved descriptors in the current GDT. */
- for_each_exec_domain(current->domain, ed) {
- if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
- (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
- (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
- goto out;
- }
- if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
- goto out;
- break;
- case PGT_ldt_page:
- if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
- goto out;
- break;
- default:
- if ( unlikely(!get_page_type(page, PGT_writable_page)) )
- goto out;
- break;
- }
-
- /* All is good so make the update. */
- gdt_pent = map_domain_mem(pa);
- memcpy(gdt_pent, d, 8);
- unmap_domain_mem(gdt_pent);
-
- put_page_type(page);
-
- ret = 0; /* success */
-
- out:
- put_page(page);
-
- UNLOCK_BIGLOCK(current->domain);
-
- return ret;
-}
-
#ifdef MEMORY_GUARD
void *memguard_init(void *heap_start)
SAVE_ALL
movq %r10,%rcx
andq $(NR_hypercalls-1),%rax
- leaq SYMBOL_NAME(hypercall_table)(%rip),%rcx
- callq *(%rcx,%rax,8)
+ leaq SYMBOL_NAME(hypercall_table)(%rip),%rbx
+ callq *(%rbx,%rax,8)
RESTORE_ALL
addq $8,%rsp
popq %rcx
SAVE_ALL
inb $0x61,%al
movl %eax,%esi # reason
- movl %esp,%edi # regs
+ movq %rsp,%rdi # regs
call SYMBOL_NAME(do_nmi)
jmp restore_all_xen
/* Returns TRUE if given descriptor is valid for GDT or LDT. */
-int check_descriptor(unsigned long *d)
+int check_descriptor(struct desc_struct *d)
{
- unsigned long base, limit, a = d[0], b = d[1];
+ u32 a = d->a, b = d->b;
/* A not-present descriptor will always fault, so is safe. */
if ( !(b & _SEGMENT_P) )
goto good;
- /*
- * We don't allow a DPL of zero. There is no legitimate reason for
- * specifying DPL==0, and it gets rather dangerous if we also accept call
- * gates (consider a call gate pointing at another guestos descriptor with
- * DPL 0 -- this would get the OS ring-0 privileges).
- */
- if ( (b & _SEGMENT_DPL) == 0 )
+ /* The guest can only safely be executed in ring 3. */
+ if ( (b & _SEGMENT_DPL) != 3 )
goto bad;
- if ( !(b & _SEGMENT_S) )
- {
- /*
- * System segment:
- * 1. Don't allow interrupt or trap gates as they belong in the IDT.
- * 2. Don't allow TSS descriptors or task gates as we don't
- * virtualise x86 tasks.
- * 3. Don't allow LDT descriptors because they're unnecessary and
- * I'm uneasy about allowing an LDT page to contain LDT
- * descriptors. In any case, Xen automatically creates the
- * required descriptor when reloading the LDT register.
- * 4. We allow call gates but they must not jump to a private segment.
- */
-
- /* Disallow everything but call gates. */
- if ( (b & _SEGMENT_TYPE) != 0xc00 )
- goto bad;
-
-#if 0
- /* Can't allow far jump to a Xen-private segment. */
- if ( !VALID_CODESEL(a>>16) )
- goto bad;
-#endif
+ /* Any code or data segment is okay. No base/limit checking. */
+ if ( (b & _SEGMENT_S) )
+ goto good;
- /* Reserved bits must be zero. */
- if ( (b & 0xe0) != 0 )
- goto bad;
-
- /* No base/limit check is needed for a call gate. */
+ /* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
+ if ( (b & _SEGMENT_TYPE) == 0x000 )
goto good;
- }
-
- /* Check that base is at least a page away from Xen-private area. */
- base = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
- if ( base >= (PAGE_OFFSET - PAGE_SIZE) )
- goto bad;
- /* Check and truncate the limit if necessary. */
- limit = (b&0xf0000) | (a&0xffff);
- limit++; /* We add one because limit is inclusive. */
- if ( (b & _SEGMENT_G) )
- limit <<= 12;
+ /* Everything but a call gate is discarded here. */
+ if ( (b & _SEGMENT_TYPE) != 0xc00 )
+ goto bad;
- if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
- {
- /*
- * Grows-down limit check.
- * NB. limit == 0xFFFFF provides no access (if G=1).
- * limit == 0x00000 provides 4GB-4kB access (if G=1).
- */
- if ( (base + limit) > base )
- {
- limit = -(base & PAGE_MASK);
- goto truncate;
- }
- }
- else
- {
- /*
- * Grows-up limit check.
- * NB. limit == 0xFFFFF provides 4GB access (if G=1).
- * limit == 0x00000 provides 4kB access (if G=1).
- */
- if ( ((base + limit) <= base) ||
- ((base + limit) > PAGE_OFFSET) )
- {
- limit = PAGE_OFFSET - base;
- truncate:
- if ( !(b & _SEGMENT_G) )
- goto bad; /* too dangerous; too hard to work out... */
- limit = (limit >> 12) - 1;
- d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
- d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
- }
- }
+ /* Can't allow far jump to a Xen-private segment. */
+ if ( !VALID_CODESEL(a>>16) )
+ goto bad;
+ /* Reserved bits must be zero. */
+ if ( (b & 0xe0) != 0 )
+ goto bad;
+
good:
return 1;
bad:
}
-void destroy_gdt(struct exec_domain *ed)
-{
- int i;
- unsigned long pfn;
-
- for ( i = 0; i < 16; i++ )
- {
- if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
- put_page_and_type(&frame_table[pfn]);
- ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
- }
-}
-
-
-long set_gdt(struct exec_domain *ed,
- unsigned long *frames,
- unsigned int entries)
-{
- struct domain *d = ed->domain;
- /* NB. There are 512 8-byte entries per GDT page. */
- int i = 0, nr_pages = (entries + 511) / 512;
- struct desc_struct *vgdt;
- unsigned long pfn;
-
- /* Check the first page in the new GDT. */
- if ( (pfn = frames[0]) >= max_page )
- goto fail;
-
- /* The first page is special because Xen owns a range of entries in it. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- {
- /* GDT checks failed: try zapping the Xen reserved entries. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
- goto fail;
- vgdt = map_domain_mem(pfn << PAGE_SHIFT);
- memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
- NR_RESERVED_GDT_ENTRIES*8);
- unmap_domain_mem(vgdt);
- put_page_and_type(&frame_table[pfn]);
-
- /* Okay, we zapped the entries. Now try the GDT checks again. */
- if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- goto fail;
- }
-
- /* Check the remaining pages in the new GDT. */
- for ( i = 1; i < nr_pages; i++ )
- if ( ((pfn = frames[i]) >= max_page) ||
- !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
- goto fail;
-
- /* Copy reserved GDT entries to the new GDT. */
- vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
- memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY,
- gdt_table + FIRST_RESERVED_GDT_ENTRY,
- NR_RESERVED_GDT_ENTRIES*8);
- unmap_domain_mem(vgdt);
-
- /* Tear down the old GDT. */
- destroy_gdt(ed);
-
- /* Install the new GDT. */
- for ( i = 0; i < nr_pages; i++ )
- ed->arch.perdomain_ptes[i] =
- mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
-
- SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
- SET_GDT_ENTRIES(ed, entries);
-
- return 0;
-
- fail:
- while ( i-- > 0 )
- put_page_and_type(&frame_table[frames[i]]);
- return -EINVAL;
-}
-
-
-long do_set_gdt(unsigned long *frame_list, unsigned int entries)
-{
- int nr_pages = (entries + 511) / 512;
- unsigned long frames[16];
- long ret;
-
- if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) )
- return -EINVAL;
-
- if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
- return -EFAULT;
-
- if ( (ret = set_gdt(current, frames, entries)) == 0 )
- {
- local_flush_tlb();
- __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
- }
-
- return ret;
-}
-
-
-long do_update_descriptor(
- unsigned long pa, unsigned long word1, unsigned long word2)
-{
- unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
- struct pfn_info *page;
- long ret = -EINVAL;
-
- d[0] = word1;
- d[1] = word2;
-
- if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) )
- return -EINVAL;
-
- page = &frame_table[pfn];
- if ( unlikely(!get_page(page, current->domain)) )
- return -EINVAL;
-
- /* Check if the given frame is in use in an unsafe context. */
- switch ( page->u.inuse.type_info & PGT_type_mask )
- {
- case PGT_gdt_page:
- /* Disallow updates of Xen-reserved descriptors in the current GDT. */
- if ( (l1_pgentry_to_pagenr(current->arch.perdomain_ptes[0]) == pfn) &&
- (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
- (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
- goto out;
- if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
- goto out;
- break;
- case PGT_ldt_page:
- if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
- goto out;
- break;
- default:
- if ( unlikely(!get_page_type(page, PGT_writable_page)) )
- goto out;
- break;
- }
-
- /* All is good so make the update. */
- gdt_pent = map_domain_mem(pa);
- memcpy(gdt_pent, d, 8);
- unmap_domain_mem(gdt_pent);
-
- put_page_type(page);
-
- ret = 0; /* success */
-
- out:
- put_page(page);
- return ret;
-}
-
#ifdef MEMORY_GUARD
#define ALLOC_PT(_level) \
ASSERT(((_p)->count_info & PGC_count_mask) != 0); \
ASSERT(page_get_owner(_p) == (_d))
-int check_descriptor(unsigned long *d);
+int check_descriptor(struct desc_struct *d);
/*
* Use currently-executing domain's pagetables on the specified CPUs.
#ifdef __x86_64__
-#define do_multicall_call(_call) BUG()
+#define do_multicall_call(_call) \
+ do { \
+ __asm__ __volatile__ ( \
+ "movq "STR(MULTICALL_op)"(%0),%%rax; " \
+ "andq $("STR(NR_hypercalls)"-1),%%rax; " \
+ "leaq "STR(hypercall_table)"(%%rip),%%rdi; "\
+ "leaq (%%rdi,%%rax,8),%%rax; " \
+ "movq "STR(MULTICALL_arg0)"(%0),%%rdi; " \
+ "movq "STR(MULTICALL_arg1)"(%0),%%rsi; " \
+ "movq "STR(MULTICALL_arg2)"(%0),%%rdx; " \
+ "movq "STR(MULTICALL_arg3)"(%0),%%rcx; " \
+ "movq "STR(MULTICALL_arg4)"(%0),%%r8; " \
+ "callq *(%%rax); " \
+ "movq %%rax,"STR(MULTICALL_result)"(%0); " \
+ : : "b" (_call) \
+ : "rax", "rdi", "rsi", "rdx", "rcx", "r8" ); \
+ } while ( 0 )
#else